from wisdoms.Memory.InterMemory import InterMemory
from wisdoms.Memory.ExterMemory import ExterMemory
from wisdoms.Memory.Swaping import Swaping
from pandas import Series
import matplotlib.pyplot as plt
class MemoryController():

    def __init__(self):
        self.InterM = InterMemory()
        self.ExterM = ExterMemory()
        self.SwapM = Swaping()

        self.PCBDict =dict()
        self.InterDict = dict()
        self.ExterDict = dict()
        self.SwapDict = dict()

    def write_process(self, PCB, size):
        '''
        free_index.tolist()
        Out[35]: [2, 3]
        t
        Out[36]:
        0    1
        1    1
        2    0
        3    0
        dtype: int64
        t[free_index.tolist()] == 1
        Out[37]:
        2    False
        3    False
        dtype: bool
        t[free_index.tolist()] = 1
        t
        Out[39]:
        0    1
        1    1
        2    1
        3    1
        dtype: int64
        :param PCB:
        :param size:
        :return:
        '''
        if size < 0: return False
        if sum(self.InterM.bitmap) == self.InterM.size:
            self.dispatch_out(size)
        self.PCBDict[PCB.PID] = PCB
        result = self.InterM.write(size)
        if type(result) == bool:
            return False #False表示没有成功申请
        elif PCB.PID not in self.InterDict.keys():
            self.InterDict[PCB.PID] = result
            return True
        else:
            '''
            dt = {'PCBID':[1,2,3]}
            dt['PCBID']+[4,5]
            Out[45]: [1, 2, 3, 4, 5]
            dt
            Out[46]: {'PCBID': [1, 2, 3]}
            dt['PCBID'] = dt['PCBID']+[4,5]
            dt
            Out[48]: {'PCBID': [1, 2, 3, 4, 5]}
            '''
            self.InterDict[PCB.PID] = self.InterDict[PCB.PID] + result
            return True

    def delete_process(self, PID, size):
        '''
        len([1,2]) = 2
        # 传入PID
        # if size => 该PID对应的内存大小:
        #	全部删除
        # else:
        #	PID对应的内存 = PID对应的内存 - size

        Example
        dt
        Out[59]: {'PCBID': [1, 2, 3, 4, 5]}

        'test' in dt.keys()
        Out[58]: False
        :param size:
        :param PID:
        :return:
        '''
        if PID in self.InterDict.keys() and size > 0 :
            #占用的内存空间可以足够
            if len(self.InterDict[PID]) >= size:
                index = self.InterDict[PID]
                # 同时将字典中对应的单元删除
                delete_index = [self.InterDict[PID].pop() for x in range(size)]
            else:
                #占用的内存空间不够，全部删掉
                delete_index = self.InterDict[PID]
                self.InterDict.pop(PID)
            self.InterM.delete(delete_index)
            return True
        return False

    #虚拟内存接口
    def dispatch_in(self,PID):
        # 先找到要从交换区调入的PCB
        if PID in self.SwapDict:
            disp_in_size = len(self.SwapDict[PID])
        else:
            disp_in_size = 0
        free_Inter_size = self.InterM.size - sum(self.InterM.bitmap)
        if disp_in_size > free_Inter_size:  #如果比要调入的进程所需空间比剩余空间大
            if PID in self.InterDict.keys(): #如果内存中本来就由一部分，那么就不要把它调出去
                object_PCB = self.PCBDict.pop(PID)
                object_Inter = self.InterDict.pop(PID)
                disp_out_result = self.dispatch_out(disp_in_size - free_Inter_size) # 调度出足够的空间
                self.PCBDict[PID] = object_PCB
                self.InterDict[PID] = object_Inter
            else:
                disp_out_result = self.dispatch_out(disp_in_size - free_Inter_size)

            if disp_out_result == False:
                return False
            else:
                write_result = self.InterM.write(disp_in_size)
                if type(write_result) == bool: #写入失败
                    return False
                else: #写入成功
                    if PID in self.InterDict.keys():    # 如果内存中本来就有一部分
                        self.InterDict[PID] = self.InterDict[PID] + write_result
                    else:   # 如果内存中没有
                        self.InterDict[PID] = write_result
                        #最后把交换区的内容删除
                    swap_index = self.SwapDict.pop(PID)
                    self.SwapM.delete(swap_index)
                    return True


    def dispatch_out(self, disp_size):
        # 默认是只调入一个进程
        # 递归的把内存中的进程调出到交换区，直到内存足够
        if disp_size > self.InterM.size:
            print("要调入内存空间的进程大于内存的总容量")
            return False
        elif disp_size <= 0:
            return True
        else:
            # 从内存中找，然后从PCBDict中取出时间等用来决策, TODO：每次调出内存
            # TODO：调度策略，目前时最久未使用最不重要的调出
            # 从所有已知的PCB中通过PID取出在内存中的PCB
            disp_PCBs = [self.PCBDict[k] for k in self.InterDict] #type: PCB
            # 按照调度策略选出一个来调度
            dispatch_indexs = [PCB.MLastTime * PCB.priority for PCB in disp_PCBs] #type: number
            # 内存中目标PCB的索引
            disp_index = dispatch_indexs.index(min(dispatch_indexs))    #type: index in PCB List
            # 内存中目标PCB的ID
            object_PCB = disp_PCBs[disp_index]
            disp_PID = self.PCBDict[object_PCB.PID].PID #type: PCB.PID
            disp_len = len(self.InterDict[disp_PID])
            #当前调出进程的空间disp_len,当前需要的总空间disp_size
            if disp_len < disp_size: # 当前目标调度进程不满足条件
                object_size = disp_size - len(self.InterDict[disp_PID])# 还需要调度出的空闲的空间
                self.delete_process(disp_PID, disp_size)# 这里是表示全部删除
                self.write_swap_process(disp_PID,disp_len) #写入到交换区
                self.dispatch_out(object_size) #递归调度
            else:   #disp_len >= disp_size
                self.delete_process(disp_PID,disp_size)
                self.write_swap_process(disp_PID,disp_size)
            return True


    # 交换区接口
    def write_swap_process(self, PID, size):
        if size < 0:return False
        result = self.SwapM.write(size)
        if type(result) == bool:
            return False #False表示没有成功申请
        elif PID not in self.SwapDict.keys():
            self.SwapDict[PID] = result
            return True
        else:
            self.SwapDict[PID] = self.SwapDict[PID] + result
            return True

    def delete_swap_process(self, PID, size):
        if size < 0:return False
        if PID in self.SwapDict.keys():
            #占用的交换空间足够
            if len(self.SwapDict[PID]) >= size:
                # 同时将字典中对应的单元删除
                delete_index = [self.SwapDict[PID].pop() for x in range(size)]
            else:
                #占用的交换空间不够，全部删掉
                delete_index = self.SwapDict[PID]
                self.SwapDict.pop(PID)
            self.SwapM.delete(delete_index)
            return True
        return False


    # 文件系统接口
    def write_file(self, filename, size):
        if size < 0: return False
        result = self.ExterM.write(size)
        if type(result) == bool:
            return False  # False表示没有成功申请
        elif filename not in self.ExterDict.keys():
            self.ExterDict[filename] = result
            return True
        else:
            self.ExterDict[filename] = self.ExterDict[filename] + result
            return True

        return False

    def delete_file(self, filename, size=100*1024):
        if filename in self.ExterDict.keys() and size >= 0:
            if len(self.ExterDict[filename]) >= size:# 删一部分
                delete_index = self.ExterDict[filename]
            else: # 如果要删除的大小比实际大小大，就全部删除
                index = self.ExterDict[filename]
                delete_index = index[0:size]
            self.InterM.delete(delete_index)
            return True
        return False

    # 界面接口
    def show(self, name='ALL'):
        if name == 'ALL':
            Inter = self.bitmap2index(self.InterM.bitmap.tolist(),"inter")
            Exter = self.bitmap2index(self.ExterM.bitmap.tolist(), "exter")
            Swap = self.bitmap2index(self.SwapM.bitmap.tolist(), "swap")
        else:
            _Inter = Series([0 for x in range(self.InterM.size)])
            _Exter = Series([0 for x in range(self.ExterM.size)])
            _Swap = Series([0 for x in range(self.SwapM.size)])
            if name in self.InterDict:
                _Inter[self.InterDict[name]] = 1
            if name in self.ExterDict:
                _Exter[self.ExterDict[name]] = 1
            if name in self.SwapDict:
                _Swap[self.SwapDict[name]] = 1

            Inter = self.bitmap2index(self._InterM.bitmap.tolist(), "inter")
            Exter = self.bitmap2index(self._ExterM.bitmap.tolist(), "exter")
            Swap = self.bitmap2index(self._SwapM.bitmap.tolist(), "swap")

        result = {}
        result["interfull"]=Inter["interfull"]
        result["interempty"]=Inter["interempty"]
        result["exterfull"]=Exter["exterfull"]
        result["exterempty"]=Exter["exterempty"]
        result["swapfull"]=Swap["swapfull"]
        result["swapempty"]=Swap["swapempty"]
        return result


    # 磁盘分配表
    def show_file(self, filename):
        return self.ExterDict[filename]

    # 内存分配表
    def show_process(self, PID):
        return self.InterDict[PID]

    #plot_bitmap
    def plot_bitmap(self, bitmap):
        '''
        bitmap = Series(data=[  0,0,0,1,
                                1,0,0,0,
                                1,1,1,0,
                                0,0,1,1])
        Bitmap = [[],[]]
        for i in range(16):
            Bitmap[0] = Bitmap[0] + [i%4]
            Bitmap[1] = Bitmap[1] + [bitmap[i] + i//4]
        :param bitmap:
        :return:
        '''
        if type(bitmap) == list:
            Bitmap = [[], [], [], []]
            for i in range(len(bitmap)):
                if bitmap[i] == 1:
                    Bitmap[0] = Bitmap[0] + [i % 256]
                    Bitmap[1] = Bitmap[1] + [bitmap[i] + i // 256]
                else:
                    Bitmap[2] = Bitmap[2] + [i % 256]
                    Bitmap[3] = Bitmap[3] + [bitmap[i] + i // 256 + 1]
            plt.figure()
            plt.scatter(Bitmap[0], Bitmap[1], marker='o', c='r')
            plt.scatter(Bitmap[2], Bitmap[3], marker='o', c='b')
            plt.grid(True)
            plt.show()
            return Bitmap

    def bitmap2index(self, bitmap, bitmap_name,col=16):
        Bitmap={}
        Bitmap[bitmap_name + "full"] = []
        Bitmap[bitmap_name + "empty"] = []
        for i in range(len(bitmap)):
            if bitmap[i] == 1:
                Bitmap[bitmap_name + "full"].append([i % col+1, bitmap[i] + i // col])
            else:
                Bitmap[bitmap_name + "empty"].append([i % col+1, bitmap[i] + i // col + 1])
        return Bitmap
class testPCB(object):

    def __init__(self, PId='test',time=0,priority=1):
        self.PID = PId
        self.MLastTime = time
        self.priority = priority

if __name__ == '__main__':
    PCB1 = testPCB('1',1,1)
    PCB2 = testPCB('2',2,1)
    PCB3 = testPCB('3',3,1)
    MC = MemoryController()
    MC.write_process(PCB1,5)
    MC.write_process(PCB2,5)
    MC.write_process(PCB3,4)
    dt = MC.show()
    MC.plot_bitmap(dt['Inter'].tolist())
    MC.plot_bitmap(dt['Swap'].tolist())
    MC.dispatch_in(PCB1.PID)
    MC.delete_process(PCB1.PID,4)
    dt = MC.show()
    MC.plot_bitmap(dt['Inter'].tolist())
    MC.plot_bitmap(dt['Swap'].tolist())
    pass